package co.fitstart.entity.product;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.Type;

import com.alibaba.fastjson.annotation.JSONField;
import com.demo2do.core.format.DecimalFormat;
import com.demo2do.core.format.PersistentFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import co.fitstart.entity.coupon.CouponBatch;
import co.fitstart.entity.course.Course;
import co.fitstart.entity.course.CourseType;
import co.fitstart.entity.course.CourseUnit;

/**
 * @author mohanlan
 * @author Leo
 */
@Entity
@Table(name="product")
@DynamicUpdate
@PersistentFormat
@JsonIgnoreProperties(value={"hibernate_lazy_initializer","handler","fieldHandler"})
public class Product {

    @Id
    @GeneratedValue
    private Long id;

    /** 产品名称 */
    private String name;

    /** 产品封面 */
    private String cover;

    /** 原价 * 100 */
    @DecimalFormat(scale = 100)
    private int basicOffer;

    /** 现价 * 100*/
    @DecimalFormat(scale = 100)
    private int currentOffer;

    /** 链接地址 */
    private String address;

    /** 二维码 (图片) */
    private String qrcode;

    /** 产品简介 */
    private String summary;

    /** 产品正文 */
    @Type(type = "text")
    @JSONField(serialize = false)
    private String description;

    /** 第三方关键字  */
    @JSONField(serialize = false)
    private String thirdParty;

    /** 销量 */
    private int salesAmount;

    /** 产品类型 */
    @Enumerated(EnumType.STRING)
    private ProductType type;

    /** 产品子类别 */
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @PersistentFormat
    private ProductCategory category;
    
    @Enumerated(EnumType.STRING)
    private CourseType courseType;
    
    @Enumerated(EnumType.STRING)
    private CourseUnit courseUnit;
    
    /** 是否线上年卡 */
    @Column(name = "is_online_year")
    @JSONField(serialize = false)
    private boolean onlineYear;

    /** 课程 */
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JSONField(serialize = false)
    @PersistentFormat
    private Course course;

    /** 可购买门店 */
    private String siteIds;

    /** 分享链接根路径 */
    private String shareUrl;

    /** 活动标签 */
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "product")
    @MapKey(name = "alias")
    private Map<String, ProductTag> tags;

    /** 上下架状态 */
    @Enumerated(EnumType.ORDINAL)
    private Status status;

    private Date onlineTime;

    private Date createTime;

    /** 权重 */
    @JSONField(serialize = false)
    private int weight;

    /** 上次编辑时间 */
    @JSONField(serialize = false)
    private Date lastUpdateTime;
    
    /** 是否导出 */
    @Column(name = "is_export")
    @JSONField(serialize = false)
    private boolean export;

    /** 是否在前台展示 */
    @Column(name = "is_display")
    @JSONField(serialize = false)
    private boolean display;

    /** 是否可购买 */
    @Column(name = "is_buyable")
    @JSONField(serialize = false)
    private boolean buyable;

    @Column(name = "is_disabled")
    @JSONField(serialize = false)
    private boolean disabled;
    
    /** 线上年卡优惠券批次 */
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @PersistentFormat
    private CouponBatch couponBatch;

    /**是否删除课程*/
    @Column(name = "is_delete")
    @JSONField(serialize = false)
    private boolean deleted;
    
    /**
     * default constructor
     */
    public Product() {

    }

    /**
     * Create product by latest
     *
     * @param latestProduct
     */
    public Product(Product latestProduct) {

        this.name = latestProduct.getName();
        this.cover = latestProduct.getCover();
        this.basicOffer = latestProduct.getBasicOffer();
        this.currentOffer = latestProduct.getCurrentOffer();
        this.address = latestProduct.getAddress();
        this.qrcode = latestProduct.getQrcode();
        this.summary = latestProduct.getSummary();
        this.description = latestProduct.getDescription();
        this.type =latestProduct.getType();
        this.category = latestProduct.getCategory();
        this.salesAmount = latestProduct.getSalesAmount();
        this.course = latestProduct.getCourse();

    }

    /**
     * @return
     */
    public Product initialize() {
        this.createTime = new Date();
        this.lastUpdateTime = this.createTime;
        this.status = Status.EDITING;
        this.weight = 0;
        this.display = true;
        this.buyable = true;
        return this;
    }
    
    public Product initializeOnlineYear() {
        this.type = ProductType.ONLINE;
        this.salesAmount = 0;
        this.onlineYear = true;
        this.createTime = new Date();
        this.lastUpdateTime = this.createTime;
        this.status = Status.EDITING;
        this.weight = 0;
        this.display = true;
        this.buyable = true;
        return this;
    }

    /**
     *
     * @param amount
     * @return
     */
    public Product increase(int amount) {
        this.salesAmount = salesAmount + amount;
        return this;
    }

    /**
     * Edit product
     *
     * @return
     */
    public Product edit() {

        // edit product type
        this.type = this.category.getType();

        // edit last update time
        this.lastUpdateTime = new Date();

        return this;
    }

    /**
     * online or offline product
     *
     * @return
     */
    public Product editStatus() {
        this.status = this.status == Status.ONLINE ? Status.OFFLINE : Status.ONLINE;
        this.onlineTime = this.status != Status.ONLINE ? new Date() : null;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * display or hide product
     *
     * @return
     */
    public Product editDisplay() {
        this.display = this.display ? false : true;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * edit buyable status
     *
     * @return
     */
    public Product editBuyable() {
        this.buyable = this.buyable ? false : true;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * edit cover
     *
     * @param cover
     * @return
     */
    public Product editCover(String cover) {
        this.cover = cover;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * edit qrcode
     *
     * @param qrcode
     * @return
     */
    public Product editQrcode(String qrcode) {
        this.qrcode = qrcode;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * edit description
     *
     * @param description
     * @return
     */
    public Product editDescription(String description) {
        this.description = description;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * edit weight
     *
     * @param tags
     * @return
     */
    public Product editWeight(List<String> tags) {

        int weight = 0;

        if(CollectionUtils.isNotEmpty(tags)) {
            for(String tag : tags) {
                weight = weight + Tag.aliasOf(tag).getWeight();
            }
        }

        this.weight = weight;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     * Down serial
     *
     * @return
     */
    public Product unstick() {
        this.weight = 100;
        this.lastUpdateTime = new Date();
        return this;
    }

    /**
     *
     * @param weight
     * @return
     */
    public Product stick(int weight) {
        this.weight = weight + 1;
        this.lastUpdateTime = new Date();
        return this;
    }
    
    /**
     * 
     * @return
     */
    public List<Long> getSiteIdsAsLong() {
        
        List<Long> ids = new ArrayList<Long>();
        
        String[] siteIdsString = StringUtils.split(siteIds, ",");
        if(siteIdsString != null && siteIdsString.length > 0) {
            for(String siteIdString : siteIdsString) {
                ids.add(Long.parseLong(siteIdString));
            }
        }
        
        return ids;
    }
    
    /**
     * Determine whether the product is available to display in detail page
     * @return
     */
    @Transient
    @JSONField(serialize = false)
    public boolean isAvailable() {
        return !this.isDisabled() && this.isDisplay() && this.status.equals(Status.ONLINE) && this.buyable;
    }

    /**
     * Determine whether the product is cooperated with third party
     * @return
     */
    @Transient
    @JSONField(serialize = false)
    public boolean isThirdPartyProduct() {
        return StringUtils.isNotBlank(this.thirdParty);
    }
    
    /**
     * 
     * @return
     */
    @Transient
    public String getProductCode() {
        String productCode = null;
        if(this.type.isOnline()) {
            if(this.course.isYear()) {
                productCode = "RMJZXS002";
            } else if (this.course.isExperience()) {
                productCode = "RMJZXS003";
            } else {
                productCode = "RMJZXS001";
            }
        } else if (this.type.isOffline()) {
            if(this.course.isYear()) {
                productCode = "RMJZXX002";
            } else if (this.course.isExperience()) {
                productCode = "RMJZXX003";
            } else {
                productCode = "RMJZXX001";
            }
        } else if (this.type.isOthers()) {
            productCode = "RMJZDS";
        }
        return productCode;
    }
    
    /**
     * 删除线上产品
     * @param deleted
     * @return
     */
    public Product deleteProduct(boolean deleted) {
    	
    	this.deleted = deleted;
    	
    	return this;    	
    }

    /**
     * @return the id
     */
    public Long getId() {
        return id;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @return the cover
     */
    public String getCover() {
        return cover;
    }

    /**
     * @return the basicOffer
     */
    public int getBasicOffer() {
        return basicOffer;
    }

    /**
     * @return the currentOffer
     */
    public int getCurrentOffer() {
        return currentOffer;
    }

    /**
     * @return the address
     */
    public String getAddress() {
        return address;
    }

    /**
     * @return the qrcode
     */
    public String getQrcode() {
        return qrcode;
    }

    /**
     * @return the summary
     */
    public String getSummary() {
        return summary;
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @return the thirdParty
     */
    public String getThirdParty() {
        return thirdParty;
    }

    /**
     * @return the salesAmount
     */
    public int getSalesAmount() {
        return salesAmount;
    }

    /**
     * @return the type
     */
    public ProductType getType() {
        return type;
    }

    /**
     * @return the category
     */
    public ProductCategory getCategory() {
        return category;
    }

    /**
     * @return the courseType
     */
    public CourseType getCourseType() {
        return courseType;
    }

    /**
     * @return the courseUnit
     */
    public CourseUnit getCourseUnit() {
        return courseUnit;
    }

    /**
     * @return the onlineYear
     */
    public boolean isOnlineYear() {
        return onlineYear;
    }

    /**
     * @return the course
     */
    public Course getCourse() {
        return course;
    }

    /**
     * @return the siteIds
     */
    public String getSiteIds() {
        return siteIds;
    }

    /**
     * @return the shareUrl
     */
    public String getShareUrl() {
        return shareUrl;
    }

    /**
     * @return the tags
     */
    public Map<String, ProductTag> getTags() {
        return tags;
    }

    /**
     * @return the status
     */
    public Status getStatus() {
        return status;
    }

    /**
     * @return the onlineTime
     */
    public Date getOnlineTime() {
        return onlineTime;
    }

    /**
     * @return the createTime
     */
    public Date getCreateTime() {
        return createTime;
    }

    /**
     * @return the weight
     */
    public int getWeight() {
        return weight;
    }

    /**
     * @return the lastUpdateTime
     */
    public Date getLastUpdateTime() {
        return lastUpdateTime;
    }

    /**
     * @return the export
     */
    public boolean isExport() {
        return export;
    }

    /**
     * @return the display
     */
    public boolean isDisplay() {
        return display;
    }

    /**
     * @return the buyable
     */
    public boolean isBuyable() {
        return buyable;
    }

    /**
     * @return the disabled
     */
    public boolean isDisabled() {
        return disabled;
    }

    /**
     * @return the couponBatch
     */
    public CouponBatch getCouponBatch() {
        return couponBatch;
    }

    /**
     * @return the deleted
     */
    public boolean isDeleted() {
        return deleted;
    }

    /**
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @param cover the cover to set
     */
    public void setCover(String cover) {
        this.cover = cover;
    }

    /**
     * @param basicOffer the basicOffer to set
     */
    public void setBasicOffer(int basicOffer) {
        this.basicOffer = basicOffer;
    }

    /**
     * @param currentOffer the currentOffer to set
     */
    public void setCurrentOffer(int currentOffer) {
        this.currentOffer = currentOffer;
    }

    /**
     * @param address the address to set
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * @param qrcode the qrcode to set
     */
    public void setQrcode(String qrcode) {
        this.qrcode = qrcode;
    }

    /**
     * @param summary the summary to set
     */
    public void setSummary(String summary) {
        this.summary = summary;
    }

    /**
     * @param description the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @param thirdParty the thirdParty to set
     */
    public void setThirdParty(String thirdParty) {
        this.thirdParty = thirdParty;
    }

    /**
     * @param salesAmount the salesAmount to set
     */
    public void setSalesAmount(int salesAmount) {
        this.salesAmount = salesAmount;
    }

    /**
     * @param type the type to set
     */
    public void setType(ProductType type) {
        this.type = type;
    }

    /**
     * @param category the category to set
     */
    public void setCategory(ProductCategory category) {
        this.category = category;
    }

    /**
     * @param courseType the courseType to set
     */
    public void setCourseType(CourseType courseType) {
        this.courseType = courseType;
    }

    /**
     * @param courseUnit the courseUnit to set
     */
    public void setCourseUnit(CourseUnit courseUnit) {
        this.courseUnit = courseUnit;
    }

    /**
     * @param onlineYear the onlineYear to set
     */
    public void setOnlineYear(boolean onlineYear) {
        this.onlineYear = onlineYear;
    }

    /**
     * @param course the course to set
     */
    public void setCourse(Course course) {
        this.course = course;
    }

    /**
     * @param siteIds the siteIds to set
     */
    public void setSiteIds(String siteIds) {
        this.siteIds = siteIds;
    }

    /**
     * @param shareUrl the shareUrl to set
     */
    public void setShareUrl(String shareUrl) {
        this.shareUrl = shareUrl;
    }

    /**
     * @param tags the tags to set
     */
    public void setTags(Map<String, ProductTag> tags) {
        this.tags = tags;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(Status status) {
        this.status = status;
    }

    /**
     * @param onlineTime the onlineTime to set
     */
    public void setOnlineTime(Date onlineTime) {
        this.onlineTime = onlineTime;
    }

    /**
     * @param createTime the createTime to set
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * @param weight the weight to set
     */
    public void setWeight(int weight) {
        this.weight = weight;
    }

    /**
     * @param lastUpdateTime the lastUpdateTime to set
     */
    public void setLastUpdateTime(Date lastUpdateTime) {
        this.lastUpdateTime = lastUpdateTime;
    }

    /**
     * @param export the export to set
     */
    public void setExport(boolean export) {
        this.export = export;
    }

    /**
     * @param display the display to set
     */
    public void setDisplay(boolean display) {
        this.display = display;
    }

    /**
     * @param buyable the buyable to set
     */
    public void setBuyable(boolean buyable) {
        this.buyable = buyable;
    }

    /**
     * @param disabled the disabled to set
     */
    public void setDisabled(boolean disabled) {
        this.disabled = disabled;
    }

    /**
     * @param couponBatch the couponBatch to set
     */
    public void setCouponBatch(CouponBatch couponBatch) {
        this.couponBatch = couponBatch;
    }

    /**
     * @param deleted the deleted to set
     */
    public void setDeleted(boolean deleted) {
        this.deleted = deleted;
    }
    
}
